package com.foftact.stockpe;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 股票估值网页解析器
 * 使用jsoup从东方财富网页抓取股票估值数据
 */
@Component
public class StockPEWebParser {
    private static final Logger logger = LoggerFactory.getLogger(StockPEWebParser.class);
    private static final String BASE_URL = "https://emweb.securities.eastmoney.com/pc_hsf10/pages/index.html?type=web&code=SZ%s&color=b#/cpbd";
    private static final int TIMEOUT_MS = 30000;
    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");

    /**
     * 从网页抓取股票估值数据
     * @param securityCode 证券代码
     * @return 股票估值数据传输对象
     */
    public StockPEWebDTO parseStockPEDataFromWeb(String securityCode) {
        if (securityCode == null || securityCode.isEmpty()) {
            logger.error("证券代码不能为空");
            return null;
        }

        try {
            // 构建URL
            String url = String.format(BASE_URL, securityCode);
            logger.info("开始抓取股票估值数据，URL: {}", url);

            // 设置请求头
            Document document = Jsoup.connect(url)
                    .userAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36")
                    .timeout(TIMEOUT_MS)
                    .get();

            // 解析股票基本信息
            StockPEWebDTO dto = parseStockInfo(document);
            if (dto == null) {
                logger.error("解析股票基本信息失败");
                return null;
            }
            dto.setSecurityCode(securityCode);
            dto.setTradeDate(new Date()); // 使用当前日期作为交易日期

            // 解析主要财务指标
            parseMainIndicators(document, dto);

            // 解析季度ROE数据
            parseRoeData(document, dto);

            logger.info("股票估值数据抓取成功，securityCode: {}", securityCode);
            return dto;
        } catch (IOException e) {
            logger.error("网络请求异常，securityCode: {}", securityCode, e);
        } catch (Exception e) {
            logger.error("解析股票估值数据异常，securityCode: {}", securityCode, e);
        }

        return null;
    }

    /**
     * 解析股票名称
     */
    private StockPEWebDTO parseStockInfo(Document document) {
        StockPEWebDTO dto = new StockPEWebDTO();
        try {
            Element stockElement = document.selectFirst("div.menus table.hqlist td.stock");
            if (stockElement != null) {
                Element stockNameElement = stockElement.selectFirst("a.stockName");
                if (stockNameElement != null) {
                    dto.setSecurityName(stockNameElement.text());
                }
            }
        } catch (Exception e) {
            logger.error("解析股票名称失败", e);
        }
        return dto;
    }

    /**
     * 解析主要财务指标
     */
    private void parseMainIndicators(Document document, StockPEWebDTO dto) {
        try {
            Element table1 = document.selectFirst("div#zxzb_table table.table1");
            if (table1 != null) {
                Elements rows = table1.select("tr");
                for (Element row : rows) {
                    Elements cells = row.select("th, td");
                    for (int i = 0; i < cells.size(); i++) {
                        String text = cells.get(i).text();
                        if (text.contains("市盈率") && text.contains("TTM") && i + 1 < cells.size()) {
                            try {
                                dto.setPeTTM(new BigDecimal(cells.get(i + 1).text()));
                            } catch (NumberFormatException e) {
                                logger.warn("解析市盈率TTM失败: {}", cells.get(i + 1).text());
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.error("解析主要财务指标失败", e);
        }
    }

    /**
     * 解析季度ROE数据
     */
    private void parseRoeData(Document document, StockPEWebDTO dto) {
        try {
            // 解析季度日期
            List<String> quarterDates = new ArrayList<>();
            Element table3 = document.selectFirst("div#zxzb_table table.table3");
            if (table3 != null) {
                Element headerRow = table3.selectFirst("tr.time");
                if (headerRow != null) {
                    Elements dateCells = headerRow.select("th.normal.txtCenter");
                    for (Element cell : dateCells) {
                        quarterDates.add(cell.text());
                    }
                }

                // 解析ROE数据
                Elements rows = table3.select("tr");
                for (Element row : rows) {
                    Elements cells = row.select("th, td");
                    if (!cells.isEmpty() && cells.get(0).text().contains("摊薄净资产收益率")) {
                        List<BigDecimal> roeValues = new ArrayList<>();
                        for (int i = 1; i < cells.size(); i++) {
                            try {
                                String value = cells.get(i).text().trim();
                                if (!value.isEmpty()) {
                                    roeValues.add(new BigDecimal(value));
                                }
                            } catch (NumberFormatException e) {
                                logger.warn("解析ROE数据失败: {}", cells.get(i).text());
                            }
                        }

                        // 计算各种ROE指标
                        calculateRoeIndicators(roeValues, dto);
                        break;
                    }
                }
            }
        } catch (Exception e) {
            logger.error("解析季度ROE数据失败", e);
        }
    }

    /**
     * 计算ROE相关指标
     */
    private void calculateRoeIndicators(List<BigDecimal> roeValues, StockPEWebDTO dto) {
        // 计算近1-4季度净资产收益率和(ROE_TTM)
        BigDecimal roeTTM = BigDecimal.ZERO;
        for (int i = 0; i < Math.min(4, roeValues.size()); i++) {
            roeTTM = roeTTM.add(roeValues.get(i));
        }
        dto.setRoeTTM(roeTTM);

        // 计算近2-5季度净资产收益率和(ROE_TTM_LAST2)
        BigDecimal roeTTMLast2 = BigDecimal.ZERO;
        for (int i = 1; i < Math.min(5, roeValues.size()); i++) {
            roeTTMLast2 = roeTTMLast2.add(roeValues.get(i));
        }
        dto.setRoeTTMLast2(roeTTMLast2);

        // 计算近5-8季度净资产收益率和(ROE_TTM_LAST5)
        BigDecimal roeTTMLast5 = BigDecimal.ZERO;
        for (int i = 4; i < Math.min(8, roeValues.size()); i++) {
            roeTTMLast5 = roeTTMLast5.add(roeValues.get(i));
        }
        dto.setRoeTTMLast5(roeTTMLast5);

        // 计算ROE_TTM_QUARTERLY = ROE_TTM / ROE_TTM_LAST2
        if (roeTTMLast2.compareTo(BigDecimal.ZERO) != 0) {
            dto.setRoeTTMQuarterly(roeTTM.divide(roeTTMLast2, 4, BigDecimal.ROUND_HALF_UP));
        }

        // 计算ROE_TTM_YEARLY = ROE_TTM / ROE_TTM_LAST5
        if (roeTTMLast5.compareTo(BigDecimal.ZERO) != 0) {
            dto.setRoeTTMYearly(roeTTM.divide(roeTTMLast5, 4, BigDecimal.ROUND_HALF_UP));
        }
        
        // 存储原始ROE数据到DTO中（如果没有从MD文件中获取）
        storeOriginalRoeData(roeValues, dto);
    }
    
    /**
     * 存储原始ROE数据到DTO中（作为从网页获取的备选方案）
     */
    private void storeOriginalRoeData(List<BigDecimal> roeValues, StockPEWebDTO dto) {
        // 只有当从MD文件未获取到数据时，才使用网页数据作为备选
        if (dto.getRoeLast1Rate() == null && !roeValues.isEmpty()) {
            // 从ROE季度数据中提取前8个季度的数据
            for (int i = 0; i < Math.min(8, roeValues.size()); i++) {
                BigDecimal rate = roeValues.get(i);
                switch (i + 1) {
                    case 1: dto.setRoeLast1Rate(rate); break;
                    case 2: dto.setRoeLast2Rate(rate); break;
                    case 3: dto.setRoeLast3Rate(rate); break;
                    case 4: dto.setRoeLast4Rate(rate); break;
                    case 5: dto.setRoeLast5Rate(rate); break;
                    case 6: dto.setRoeLast6Rate(rate); break;
                    case 7: dto.setRoeLast7Rate(rate); break;
                    case 8: dto.setRoeLast8Rate(rate); break;
                }
            }
        }
    }
    
}